package com.galaxy.map.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.galaxy.common.core.exception.ServiceException;
import com.galaxy.map.config.AmapConfig;
import com.galaxy.map.model.dto.LocationDTO;
import com.galaxy.map.model.dto.PoiDTO;
import com.galaxy.map.model.dto.RouteDTO;
import com.galaxy.map.model.vo.DistrictVO;
import com.galaxy.map.model.vo.GeocodeVO;
import com.galaxy.map.model.vo.RegeocodeVO;
import com.galaxy.map.model.vo.RouteVO;
import com.galaxy.map.service.IMapService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import cn.hutool.http.HttpUtil;
import jakarta.servlet.http.HttpServletRequest;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 地图服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MapServiceImpl implements IMapService {

    private final AmapConfig amapConfig;
    private final HttpServletRequest request;

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIp() {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 多个代理的情况，第一个IP为客户端真实IP
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0];
        }

        return ip;
    }

    /**
     * 获取公网IP地址
     */
    private String getPublicIp() {
        try {
            URL url = new URL("https://httpbin.org/ip");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // 解析JSON响应以获取IP地址
                String ipAddress = response.toString().split("\"origin\": \"")[1].split("\"")[0];
                return ipAddress;
            } else {
                System.out.println("GET request not worked");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 如果获取失败，使用备用IP
        return "114.247.50.2";
    }

    @Override
    public Double calculateDistance(Double fromLongitude, Double fromLatitude, Double toLongitude, Double toLatitude) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("origins", fromLongitude + "," + fromLatitude);
            params.put("destination", toLongitude + "," + toLatitude);
            params.put("type", "1"); // 1表示直线距离，0表示驾车距离

            // 发送请求
            String response = HttpUtil.get("https://restapi.amap.com/v3/distance", params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (json.getInteger("status") != 1) {
                throw new ServiceException("计算距离失败：" + json.getString("info"));
            }

            // 获取距离（米）
            return Double.parseDouble(json.getJSONArray("results").getJSONObject(0).getString("distance"));
        } catch (Exception e) {
            log.error("计算距离异常", e);
            throw new ServiceException("计算距离失败：" + e.getMessage());
        }
    }

    @Override
    public GeocodeVO geocode(String address, String city) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("address", address);
            if (city != null && !city.isEmpty()) {
                params.put("city", city);
            }

            // 发送请求
            String response = HttpUtil.get(amapConfig.getGeocodeUrl(), params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (json.getInteger("status") != 1) {
                throw new ServiceException("地理编码失败：" + json.getString("info"));
            }

            // 构建返回结果
            GeocodeVO geocodeVO = new GeocodeVO();
            JSONObject geocode = json.getJSONArray("geocodes").getJSONObject(0);
            String[] location = geocode.getString("location").split(",");
            geocodeVO.setLongitude(Double.parseDouble(location[0]));
            geocodeVO.setLatitude(Double.parseDouble(location[1]));
            geocodeVO.setFormattedAddress(geocode.getString("formatted_address"));
            geocodeVO.setProvince(geocode.getString("province"));
            geocodeVO.setCity(geocode.getString("city"));
            geocodeVO.setDistrict(geocode.getString("district"));
            geocodeVO.setStreet(geocode.getString("street"));
            geocodeVO.setStreetNumber(geocode.getString("street_number"));

            return geocodeVO;
        } catch (Exception e) {
            log.error("地理编码异常", e);
            throw new ServiceException("地理编码失败：" + e.getMessage());
        }
    }

    @Override
    public RegeocodeVO regeocode(LocationDTO location) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("location", location.getLongitude() + "," + location.getLatitude());
            params.put("extensions", "all");

            // 发送请求
            String response = HttpUtil.get(amapConfig.getRegeocodeUrl(), params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (json.getInteger("status") != 1) {
                throw new ServiceException("逆地理编码失败：" + json.getString("info"));
            }

            // 构建返回结果
            RegeocodeVO regeocodeVO = new RegeocodeVO();
            JSONObject regeocode = json.getJSONObject("regeocode");
            JSONObject addressComponent = regeocode.getJSONObject("addressComponent");

            regeocodeVO.setFormattedAddress(regeocode.getString("formatted_address"));
            regeocodeVO.setProvince(addressComponent.getString("province"));
            regeocodeVO.setCity(addressComponent.getString("city"));
            regeocodeVO.setDistrict(addressComponent.getString("district"));
            regeocodeVO.setStreet(addressComponent.getString("street"));
            regeocodeVO.setStreetNumber(addressComponent.getString("streetNumber"));

            // 获取最近的兴趣点
            JSONArray pois = regeocode.getJSONArray("pois");
            if (pois != null && !pois.isEmpty()) {
                JSONObject poi = pois.getJSONObject(0);
                regeocodeVO.setPoi(poi.getString("name"));
                regeocodeVO.setPoiType(poi.getString("type"));
                regeocodeVO.setPoiDistance(poi.getInteger("distance"));
            }

            return regeocodeVO;
        } catch (Exception e) {
            log.error("逆地理编码异常", e);
            throw new ServiceException("逆地理编码失败：" + e.getMessage());
        }
    }

    @Override
    public List<DistrictVO> getDistricts(String keywords, Integer subdistrict) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("keywords", keywords);
            params.put("subdistrict", subdistrict);

            // 发送请求
            String response = HttpUtil.get(amapConfig.getDistrictUrl(), params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (json.getInteger("status") != 1) {
                throw new ServiceException("获取行政区划失败：" + json.getString("info"));
            }

            // 构建返回结果
            List<DistrictVO> districts = new ArrayList<>();
            JSONArray districtsArray = json.getJSONArray("districts");
            for (int i = 0; i < districtsArray.size(); i++) {
                JSONObject district = districtsArray.getJSONObject(i);
                DistrictVO districtVO = new DistrictVO();
                districtVO.setAdcode(district.getString("adcode"));
                districtVO.setName(district.getString("name"));
                districtVO.setLevel(district.getString("level"));
                districtVO.setCenter(district.getString("center"));
                districtVO.setPolyline(district.getString("polyline"));

                // 递归处理下级行政区
                JSONArray subDistricts = district.getJSONArray("districts");
                if (subDistricts != null && !subDistricts.isEmpty()) {
                    List<DistrictVO> subDistrictList = new ArrayList<>();
                    for (int j = 0; j < subDistricts.size(); j++) {
                        JSONObject subDistrict = subDistricts.getJSONObject(j);
                        DistrictVO subDistrictVO = new DistrictVO();
                        subDistrictVO.setAdcode(subDistrict.getString("adcode"));
                        subDistrictVO.setName(subDistrict.getString("name"));
                        subDistrictVO.setLevel(subDistrict.getString("level"));
                        subDistrictVO.setCenter(subDistrict.getString("center"));
                        subDistrictVO.setPolyline(subDistrict.getString("polyline"));
                        subDistrictList.add(subDistrictVO);
                    }
                    districtVO.setDistricts(subDistrictList);
                }

                districts.add(districtVO);
            }

            return districts;
        } catch (Exception e) {
            log.error("获取行政区划异常", e);
            throw new ServiceException("获取行政区划失败：" + e.getMessage());
        }
    }

    @Override
    public List<PoiDTO> searchAround(LocationDTO location, String keywords, Integer radius) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("location", location.getLongitude() + "," + location.getLatitude());
            params.put("keywords", keywords);
            params.put("radius", radius);
            params.put("extensions", "all");

            // 发送请求
            String response = HttpUtil.get(amapConfig.getAroundUrl(), params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (json.getInteger("status") != 1) {
                throw new ServiceException("周边搜索失败：" + json.getString("info"));
            }

            // 构建返回结果
            List<PoiDTO> pois = new ArrayList<>();
            JSONArray poisArray = json.getJSONArray("pois");
            for (int i = 0; i < poisArray.size(); i++) {
                JSONObject poi = poisArray.getJSONObject(i);
                PoiDTO poiDTO = new PoiDTO();
                poiDTO.setId(poi.getString("id"));
                poiDTO.setName(poi.getString("name"));
                poiDTO.setType(poi.getString("type"));
                poiDTO.setTypecode(poi.getString("typecode"));
                poiDTO.setAddress(poi.getString("address"));
                poiDTO.setLocation(poi.getString("location"));
                poiDTO.setTel(poi.getString("tel"));
                poiDTO.setDistance(poi.getInteger("distance"));
                poiDTO.setBusinessHours(poi.getString("business_hours"));
                poiDTO.setRating(poi.getString("rating"));
                pois.add(poiDTO);
            }

            return pois;
        } catch (Exception e) {
            log.error("周边搜索异常", e);
            throw new ServiceException("周边搜索失败：" + e.getMessage());
        }
    }

    @Override
    public RouteVO planWalkingRoute(LocationDTO origin, LocationDTO destination) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("origin", origin.getLongitude() + "," + origin.getLatitude());
            params.put("destination", destination.getLongitude() + "," + destination.getLatitude());

            // 发送请求
            String response = HttpUtil.get(amapConfig.getWalkingUrl(), params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (json.getInteger("status") != 1) {
                throw new ServiceException("步行路线规划失败：" + json.getString("info"));
            }

            // 构建返回结果
            RouteVO routeVO = new RouteVO();
            JSONObject route = json.getJSONObject("route");
            routeVO.setDistance(route.getInteger("distance"));
            routeVO.setDuration(route.getInteger("duration"));

            List<RouteDTO> steps = new ArrayList<>();
            JSONArray paths = route.getJSONArray("paths");
            if (paths != null && !paths.isEmpty()) {
                JSONObject path = paths.getJSONObject(0);
                JSONArray stepsArray = path.getJSONArray("steps");
                for (int i = 0; i < stepsArray.size(); i++) {
                    JSONObject step = stepsArray.getJSONObject(i);
                    RouteDTO stepDTO = new RouteDTO();
                    stepDTO.setDistance(step.getInteger("distance"));
                    stepDTO.setDuration(step.getInteger("duration"));
                    stepDTO.setInstruction(step.getString("instruction"));
                    stepDTO.setOrientation(step.getString("orientation"));
                    stepDTO.setRoad(step.getString("road"));
                    stepDTO.setPolyline(step.getString("polyline"));
                    steps.add(stepDTO);
                }
            }
            routeVO.setSteps(steps);

            return routeVO;
        } catch (Exception e) {
            log.error("步行路线规划异常", e);
            throw new ServiceException("步行路线规划失败：" + e.getMessage());
        }
    }

    @Override
    public LocationDTO getLocationByIp(String ip) {
        try {
            // 如果IP为空，则获取客户端IP
            if (ip == null || ip.isEmpty()) {
                ip = getClientIp();
                log.info("客户端IP地址：{}", ip);
            }

            // 如果是本地IP，则获取公网IP
            if ("127.0.0.1".equals(ip) || "localhost".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
                ip = getPublicIp();
                log.info("检测到本地IP，使用公网IP：{}", ip);
            }

            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("key", amapConfig.getKey());
            params.put("ip", ip);

            // 发送请求
            String response = HttpUtil.get(amapConfig.getIpUrl(), params);

            // 解析响应
            JSONObject json = JSONObject.parseObject(response);
            if (!"1".equals(json.getString("status"))) {
                throw new ServiceException("IP定位失败：" + json.getString("info"));
            }

            // 构建返回结果
            LocationDTO location = new LocationDTO();

            // 设置区域范围信息
            String rectangle = json.getString("rectangle");
            if (rectangle != null && !rectangle.isEmpty()) {
                String[] points = rectangle.split(";");
                if (points.length == 2) {
                    location.setSwPoint(points[0]); // 西南角坐标
                    location.setNePoint(points[1]); // 东北角坐标
                    location.setRectangle(rectangle); // 完整矩形
                }
            }

            location.setProvince(json.getString("province"));
            location.setCity(json.getString("city"));
            location.setDistrict(json.getString("adcode")); // 使用adcode作为区县编码
            location.setAddress(json.getString("province") + json.getString("city")); // 组合省市区作为地址

            return location;
        } catch (Exception e) {
            log.error("IP定位异常", e);
            throw new ServiceException("IP定位失败：" + e.getMessage());
        }
    }

    @Override
    public String getIp() {
        String ip = getClientIp();
        // 如果是本地IP，则获取公网IP
        if ("127.0.0.1".equals(ip) || "localhost".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            ip = getPublicIp();

            log.info("检测到本地IP，使用公网IP：{}", ip);
        }
        return ip;
    }
}
